package org.jheuristics.ga.operators.reproductors;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import org.epanetgrid.otimizacao.util.OtimizacaoUtil;
import org.jheuristics.Individual;
import org.jheuristics.ga.GAConfig;
import org.jheuristics.ga.GAStatus;
import org.jheuristics.ga.operators.Probability;
import org.jheuristics.ga.operators.Reproductor;
import org.jheuristics.util.BitString;


/**
 * TODO
 *
 * @author Marcell Manfrin, marcell at ourgrid.org, 2005
 */
public abstract class AbstractGensListMutation extends AbstractMutation {

	/**
	 * TODO
	 *
	 * @param probability
	 * @param tryOuts
	 */
	public AbstractGensListMutation(Probability probability, int tryOuts) {
		super(probability, tryOuts);
	}

	/**
	 * TODO
	 *
	 * @param decoretedReproductor
	 * @param probability
	 * @param tryOuts
	 */
	public AbstractGensListMutation(Reproductor decoretedReproductor, Probability probability, int tryOuts) {
		super(decoretedReproductor, probability, tryOuts);
	}

	/**
	 * TODO
	 *
	 * @param individual
	 * @param status
	 * @param config
	 * @return
	 * @see org.jheuristics.ga.operators.reproductors.AbstractMutation#mutate(org.jheuristics.Individual, org.jheuristics.ga.GAStatus, org.jheuristics.ga.GAConfig)
	 */
	protected Individual mutate(Individual individual, GAStatus status, GAConfig config) {
		
		StringBuffer buffer = new StringBuffer();
		
		buffer.append("Cromossomo enviado para Muta��o normal (bit a bit): ");
		buffer.append(individual);
		buffer.append("\n");
		
		logger.debug(buffer);
		
		buffer = new StringBuffer();
		
		Object genMutaded = mutate((List) individual.getGens(), status, config);
		
		buffer = new StringBuffer();
        // did mutation happen?
        if (null != genMutaded) {
        	buffer.append("Cromossomo mutado: ");
    		buffer.append(OtimizacaoUtil.gensToString((List<BitString>) genMutaded));
    		buffer.append("\n");
    		logger.debug(buffer);
    		
    		Individual mutado = config.getIndividualsFactory().createSpecificIndividual(genMutaded, config);
    	    
    		//FIXME: possivel corre��o para a perda do data application de individuos j� simulados
    	    
    	    if(mutado.getGens().equals(individual.getGens())){
    	    	mutado.setDataApplication(individual.getDataApplication());
    	    	mutado.setFitness(individual.getFitness());
    	    }

    	    ///////////////////////////////
            return mutado;
        } else {
        	buffer.append("Cromossomo n�o sofreu muta��o: ");
    		buffer.append("\n");
    		logger.debug(buffer);
            return individual;
        }
	}

	/**
	 * TODO
	 *
	 * @param gens
	 * @param status
	 * @param config
	 * @return
	 */
	private Object mutate(List gens, GAStatus status, GAConfig config) {
		List newGens = new LinkedList();
		int cont = 1;
		for (Iterator it = gens.iterator(); it.hasNext(); ) {
			Object gen = it.next();
			StringBuffer buffer  = new StringBuffer("Intervalo: ");
			buffer.append(cont++);
			logger.debug(buffer);
			newGens.add(mutate(gen, status, config));
		}
		if (!gens.equals(newGens)) {
			return newGens;
		}
		return null;
	}

	/**
	 * TODO
	 *
	 * @param object
	 * @param status
	 * @param config
	 * @return
	 */
	protected abstract Object mutate(Object object, GAStatus status, GAConfig config);

}
